package com.ww.springboot.boot.thread.study.base.lock;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.IntConsumer;

/**
 * 1把锁 一起执行 不满足条件的锁等待 满足条件的打印并唤醒所有锁 比四把多执行逻辑
 */
class FizzBuzz2 {
    private int n;
    private int i=1;
    private Lock lock=new ReentrantLock();
    private Condition condition=lock.newCondition();

    public FizzBuzz2(int n) {
        this.n = n;
    }

    // printFizz.run() outputs "fizz".
    public void fizz(Runnable printFizz) throws InterruptedException {
        while(i<=n){
            lock.lock();
            if(i%3==0&&i%5!=0){
                printFizz.run();
                i++;
                condition.signalAll();
            }
            else{
                condition.await();
            }
            lock.unlock();
        }          
        
    }

    // printBuzz.run() outputs "buzz".
    public void buzz(Runnable printBuzz) throws InterruptedException {
        while(i<=n){
            lock.lock();
            if(i%5==0&&i%3!=0){
                printBuzz.run();
                i++;
                condition.signalAll();
            }
            else{
                condition.await();
            }
            lock.unlock();
        }          
    }

    // printFizzBuzz.run() outputs "fizzbuzz".
    public void fizzbuzz(Runnable printFizzBuzz) throws InterruptedException {
        while(i<=n){
            lock.lock();
            if(i%3==0&&i%5==0){
                printFizzBuzz.run();
                i++;
                condition.signalAll();
            }
            else{
                condition.await();
            }
            lock.unlock();
        }          
    }

    // printNumber.accept(x) outputs "x", where x is an integer.
    public void number(IntConsumer printNumber) throws InterruptedException {
        while(i<=n){
            lock.lock();
            if(i%3!=0&&i%5!=0){
                printNumber.accept(i);
                i++;
                condition.signalAll();
            }
            else{
                condition.await();
            }
            lock.unlock();
        }          
    }

    public static void main(String[] args) throws InterruptedException {
        FizzBuzz2 fizzBuzz2 = new FizzBuzz2(15);
        new Thread(()->{
            try {
                fizzBuzz2.buzz(new PrintFizz());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        new Thread(()->{
            try {
                fizzBuzz2.fizz(new PrintBuzz());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        new Thread(()->{
            try {
                fizzBuzz2.fizzbuzz(new Fizzbuzz());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        new Thread(()->{
            try {
                fizzBuzz2.number(value -> System.out.println(value));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }

    static class PrintFizz implements Runnable {
        @Override
        public void run() {
            System.out.println("fizz");
        }
    }

    static class PrintBuzz implements Runnable {
        @Override
        public void run() {
            System.out.println("buzz");
        }
    }

    static class Fizzbuzz implements Runnable {
        @Override
        public void run() {
            System.out.println("fizzbuzz");
        }
    }
}
